/*
 * Copyright (c) 1995, 2008, Oracle and/or its affiliates. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Oracle or the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * GUI test
 * 
 * @author Benjamin Adcock
 */

package hms.employees;

import hms.generic.AbstractGlobalView;
import hms.UserAccountsModule.UserAccount;
import hms.UserAccountsModule.UserAccountControl;
import hms.database.DBJFrame;
import hms.date.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class EmployeeView extends AbstractGlobalView implements ListSelectionListener {


	final String[] months = {"Janurary", "February", "March", "April", "May", "June",
			"July","August","September","October","November","December"};
	
	///////////////////////////
	//// Global GUI Fields ////
	///////////////////////////
	
	private JTextField firstNameField;
	private JTextField lastNameField;
	private JComboBox hireMonthBox;
	private JComboBox hireDayBox;
	private JFormattedTextField hireYearBox;
	private JComboBox jobTitleBox;
	private JCheckBox terminatedCheck;
	private JComboBox fireMonthBox;
	private JComboBox fireDayBox;
	private JFormattedTextField fireYearBox;
	private JComboBox terminationReasonBox;
	private JList employeeList;
	private JButton linkButton;
	private JButton removeButton;
	private JButton commitButton;
	
	private HireHandler hireProxy;
	private DateHandler fireProxy;
	private EmployeeControl allEmployees;
	private UserAccountControl uac;
	private Employee currentEmployee;
	private DefaultListModel listModel;
	private JobTitleList jobTitleList;
	private TerminationReasonList terminationReasonList;

	/////////////////////
	//// Constructor ////
	/////////////////////
	
	public EmployeeView() {

		// Load employees
		allEmployees = new EmployeeControl();
		uac = new UserAccountControl();
		
		//////////////////////////////////////////////////////
		//// Create GUI elements and listener assignments ////
		//////////////////////////////////////////////////////
		
		JLabel firstNameLabel = new JLabel("First Name");
		JLabel lastNameLabel = new JLabel("Last Name");
		JLabel hireDateLabel = new JLabel("Hire Date");
		JLabel jobTitleLabel = new JLabel("Job Title");
		JLabel terminatedLabel = new JLabel("Terminated");
		JLabel terminationDateLabel = new JLabel("Termination Date");
		JLabel terminationReasonLabel = new JLabel("Reason for Termination");
		
		firstNameField = new JTextField();
		firstNameField.getDocument().addDocumentListener(new FirstNameHandler());
		firstNameField.getDocument().addDocumentListener(new ChangeHandler());
		
		lastNameField = new JTextField();
		lastNameField.getDocument().addDocumentListener(new LastNameHandler());
		lastNameField.getDocument().addDocumentListener(new ChangeHandler());
		
		fireDayBox = new JComboBox();
		fireMonthBox = new JComboBox(months);
		fireYearBox = new JFormattedTextField(new DecimalFormat("####"));
		fireProxy = new FireHandler(fireMonthBox, fireDayBox, fireYearBox);
		
		hireDayBox = new JComboBox();
		hireMonthBox = new JComboBox(months);
		hireYearBox = new JFormattedTextField(new DecimalFormat("####"));
		hireProxy = new HireHandler(hireMonthBox, hireDayBox, hireYearBox);
		
		jobTitleList = new JobTitleList();
		jobTitleList.fillFromDatabase();
		jobTitleBox = new JComboBox(jobTitleList.toArray());
		jobTitleBox.setEditable(true);
		jobTitleBox.addActionListener(new JobTitleHandler());
		
		terminationReasonList = new TerminationReasonList();
		terminationReasonList.fillFromDatabase();
		terminationReasonBox = new JComboBox(terminationReasonList.toArray());
		terminationReasonBox.setEditable( true );
		terminationReasonBox.addActionListener(new TerminationHandler());
		
		terminatedCheck = new JCheckBox();
		terminatedCheck.addActionListener(new TerminationCheckHandler());
		
		listModel = new DefaultListModel();
		syncListModel();
		employeeList = new JList(listModel);
		employeeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		employeeList.addListSelectionListener( this );
		employeeList.setLayoutOrientation(JList.VERTICAL);
		JScrollPane pane = new JScrollPane(employeeList);
		
		JButton addButton = new JButton("Add...");
		addButton.addActionListener(new AddListener());
		
		removeButton = new JButton("Remove");
		removeButton.addActionListener(new RemoveListener());
		
		commitButton = new JButton("Commit To DB");
		commitButton.addActionListener(new CommitListener());
		
		linkButton = new JButton("Link");
		linkButton.addActionListener(new LinkListener());
		

		//////////////////////////////////
		//// Create and Layout Panels ////
		//////////////////////////////////
		
		JPanel hrPanel = new JPanel();
		hrPanel.setLayout(new GridBagLayout());
		GridBagConstraints c;
		
		c = new GridBagConstraints();
		c.gridx = 0;
		c.weightx = .2;
		c.weighty = .2;
		c.anchor = GridBagConstraints.LINE_END;
		c.insets = new Insets(10, 10, 10, 10);
		c.fill = GridBagConstraints.BOTH;
		
		c.gridy = 0; hrPanel.add(hireDateLabel, c);
		c.gridy = 1; hrPanel.add(jobTitleLabel, c);
		c.gridy = 2; hrPanel.add(terminatedLabel, c);
		c.gridy = 3; hrPanel.add(terminationDateLabel, c);
		c.gridy = 4; hrPanel.add(terminationReasonLabel, c);
		
		c.anchor = GridBagConstraints.CENTER;

		c.gridx = 1; c.gridy = 0; c.gridwidth = 1; hrPanel.add(hireMonthBox,c);
		c.gridx = 1; c.gridy = 1; c.gridwidth = 3; hrPanel.add(jobTitleBox,c);
		c.gridx = 1; c.gridy = 2; c.gridwidth = 1; hrPanel.add(terminatedCheck,c);
		c.gridx = 1; c.gridy = 3; c.gridwidth = 1; hrPanel.add(fireMonthBox,c);
		c.gridx = 1; c.gridy = 4; c.gridwidth = 3; hrPanel.add(terminationReasonBox,c);
		c.gridx = 2; c.gridy = 0; c.gridwidth = 1; hrPanel.add(hireDayBox,c);
		c.gridx = 2; c.gridy = 3; hrPanel.add(fireDayBox,c);
		c.gridx = 3; c.gridy = 0; hrPanel.add(hireYearBox,c);
		c.gridx = 3; c.gridy = 3; hrPanel.add(fireYearBox,c);
		

		hrPanel.setBorder(BorderFactory.createTitledBorder("HR Information"));
		
		/////////////////////
		//// Main Layout ////
		/////////////////////
		
		JPanel panel = new JPanel();
		panel.setLayout(new GridBagLayout()); // Set layout to GridBagLayout style
		

		c.anchor = GridBagConstraints.LINE_END;
		
		c.gridx = 0; c.gridy = 0; 
		c.weightx = .1;
		c.gridwidth = 1;
		c.gridheight = 1;
		panel.add(firstNameLabel,c);
		c.gridx = 0; c.gridy = 1; panel.add(lastNameLabel, c);
		c.weightx = .5;
		c.anchor = GridBagConstraints.CENTER;
		c.gridx = 0; c.gridy = 2; c.gridwidth = 2; panel.add(hrPanel,c);

		c.weightx = .4;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.gridx = 1; c.gridy = 0; c.gridwidth = 1; panel.add(firstNameField,c);
		c.gridx = 1; c.gridy = 1; panel.add(lastNameField,c);
		
        c.weightx = .25;
		c.fill = GridBagConstraints.BOTH;
		c.gridx = 3;
		c.gridy = 0;
		c.gridwidth = 2;
		c.gridheight = 3;
		panel.add(pane, c);
		
		c.gridx = 3;
		c.gridy = 3;
		c.gridwidth = 1;
		c.gridheight = 1;
		panel.add(addButton, c);
		c.gridx = 4;
		panel.add(removeButton, c);
		c.gridy = 4;
		panel.add(commitButton, c);
		c.gridx = 3;
		panel.add(linkButton, c);
		

		///////////////////////
		//// Display Panel ////
		///////////////////////
		updateGUI();
		informationHasBeenSaved();
		commitButton.setEnabled(false);
		
		super.update(panel);
		super.display();
	}

	/////////////////////////////////////////
	//// Convenience Classes and Methods ////
	/////////////////////////////////////////
	
	
	
	private void updateGUI() {
		boolean changed = commitButton.isEnabled();
		if(currentEmployee==null) {
			firstNameField.setEnabled(false);
				lastNameField.setEnabled(false);
				hireProxy.setEnabled(false);
				fireProxy.setEnabled(false);
				jobTitleBox.setEnabled(false);
				terminatedCheck.setEnabled(false);
				terminationReasonBox.setEnabled(false);
				removeButton.setEnabled(false);
				linkButton.setEnabled(false);
		} else {

			firstNameField.setEnabled(true);
				lastNameField.setEnabled(true);
				jobTitleBox.setEnabled(true);
				terminatedCheck.setEnabled(true);
				hireProxy.setEnabled(true);
				fireProxy.setEnabled(currentEmployee.isTerminated());
				terminationReasonBox.setEnabled(currentEmployee.isTerminated());
				firstNameField.setText(currentEmployee.getFirstName());
			lastNameField.setText(currentEmployee.getLastName());
			hireProxy.setDate(currentEmployee.getHireMonth(),
					currentEmployee.getHireDay(),
					currentEmployee.getHireYear());
			fireProxy.setDate(currentEmployee.getFireMonth(),
					currentEmployee.getFireDay(),
					currentEmployee.getFireYear());
			int index = jobTitleList.getStringList().indexOf(currentEmployee.getPosition());
			jobTitleBox.setSelectedIndex(index);
			//jobTitleBox.setSelectedItem(currentEmployee.getPosition());
			terminationReasonBox.setSelectedItem(currentEmployee.getTerminationReason());
			terminatedCheck.setSelected(currentEmployee.isTerminated());

			removeButton.setEnabled(true);
			linkButton.setEnabled(true);
		}
		if(!changed) {
			commitButton.setEnabled(false);
			informationHasBeenSaved();
		}
	}
	
	///////////////////////////////////////
	//// List Selection Handler Method ////
	///////////////////////////////////////
	

	@Override
	public void valueChanged(ListSelectionEvent arg0) {
		if(arg0.getValueIsAdjusting() == false) {
			int index = employeeList.getSelectedIndex();
			if( index == -1 ) {
				currentEmployee = null;
			} else {
				currentEmployee = (Employee) listModel.get(index);
			}
			updateGUI();
		}
	}
	
	////////////////////////////////
	//// Data Integrity Methods ////
	////////////////////////////////
	
	@Override
	public void informationWillBeLost() {
		super.informationWillBeLost();
		commitButton.setEnabled(true);
	}
	
	private void syncListModel() {
		listModel.clear();
		//ArrayList<Employee> reducedSet = allEmployees.notQueuedForDeletion();
		listModel.ensureCapacity(allEmployees.size());
		for(Employee e : allEmployees) {
			if(!e.isMarkedForDeletion()&&!e.isDefault()) {
				listModel.addElement(e);
			}
		}
	}
	
	//////////////////////////////
	//// Listener Definitions ////
	//////////////////////////////
	
	class FirstNameHandler implements DocumentListener {
		@Override
		public void changedUpdate(DocumentEvent arg0) {
		}

		@Override
		public void insertUpdate(DocumentEvent arg0) {
			currentEmployee.setFirstName(firstNameField.getText());
		}

		@Override
		public void removeUpdate(DocumentEvent arg0) {
			currentEmployee.setFirstName(firstNameField.getText());
		}
	}
	
	class LastNameHandler implements DocumentListener {
		@Override
		public void changedUpdate(DocumentEvent arg0) {
		}
		@Override
		public void insertUpdate(DocumentEvent arg0) {
			currentEmployee.setLastName(lastNameField.getText());
			
		}
		@Override
		public void removeUpdate(DocumentEvent arg0) {
			currentEmployee.setLastName(lastNameField.getText());
			
		}	
	}
	
	class ChangeHandler implements ActionListener, DocumentListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			updateGUI();
			informationWillBeLost();
		}
		
        //Required by DocumentListener.
        public void insertUpdate(DocumentEvent e) {

			informationWillBeLost();
        }

        //Required by DocumentListener.
        public void removeUpdate(DocumentEvent e) {
        	// TODO [ben] handle blank fields
			informationWillBeLost();
        }

        //Required by DocumentListener.
        public void changedUpdate(DocumentEvent e) {

			informationWillBeLost();
        }
		
	}
	
	
	
	class HireHandler extends DateHandler {
		public HireHandler(JComboBox month, JComboBox day,
				JFormattedTextField year) {
			super(month, day, year);
		}

		@Override
		public void writeOut(int year, int month, int day) {
			currentEmployee.setHireDate(year, month, day);
		}
		
		
	}
	
	class FireHandler extends DateHandler {
		public FireHandler(JComboBox month, JComboBox day,
				JFormattedTextField year) {
			super(month, day, year);
			
		}

		@Override
		public void writeOut(int year, int month, int day) {
			currentEmployee.setTerminationDate(year, month, day);
		}
		
		@Override
		public void actionPerformed(ActionEvent e){
			if(fireProxy.getDate().before(hireProxy.getDate())) {
				fireProxy.setDate(hireProxy.getDate());
			}
			super.actionPerformed(e);
		}
	
	}
	
	class TerminationCheckHandler implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			currentEmployee.setTerminated(terminatedCheck.isSelected());

			updateGUI();
			informationWillBeLost();
		}
		
	}
	
	class JobTitleHandler implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			// TODO Auto-generated method stub
			currentEmployee.setPosition(jobTitleBox.getSelectedItem().toString());
			JobTitle newTitle = new JobTitle(jobTitleBox.getSelectedItem().toString());
			boolean unique = true;
			for(JobTitle jt : jobTitleList) {
				if(jt.getJobTitle().contentEquals(newTitle.getJobTitle())) {
					unique = false;
					break;
				}
			}
			if(unique) {
				jobTitleList.add(newTitle);
				int index = jobTitleBox.getItemCount();
				jobTitleBox.addItem(newTitle.getJobTitle());
				jobTitleBox.setSelectedIndex(index);
			}
			currentEmployee.setPosition(newTitle.getJobTitle());

			updateGUI();
			informationWillBeLost();
		}
		
	}
	
	class TerminationHandler implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent e) {
			currentEmployee.setTerminationReason(terminationReasonBox.getSelectedItem().toString());
			TerminationReason newReason = new TerminationReason(terminationReasonBox.getSelectedItem().toString());
			boolean unique = true;
			for(TerminationReason reason  : terminationReasonList) {
				if(reason.getTerminationReasonString().equals(newReason.getTerminationReasonString())) {
				unique = false;
				break;
			}
			}
			if(unique) {
				terminationReasonList.add(newReason);
				terminationReasonBox.addItem(newReason.getTerminationReasonString());
			}

			updateGUI();
			informationWillBeLost();
		}
		
	}
	
	class AddListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			currentEmployee = new Employee();
			currentEmployee.setFirstName("New");
			currentEmployee.setLastName("Employee");
			int index = allEmployees.size();
			allEmployees.add(currentEmployee);
			syncListModel();
			employeeList.setSelectedIndex(index);
			employeeList.ensureIndexIsVisible(index);
		}
	}
	
	class RemoveListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			if(uac.isEmployeeLinked(currentEmployee)) {
				UserAccount ua = uac.getLinkedUserAccount(currentEmployee);
				ua.unlinkEmployee();
			}
			int index = employeeList.getSelectedIndex();
			currentEmployee.markToBeDeleted();
			currentEmployee = null;
			
			// Update display
			syncListModel();
			// Mark data as tentative
			informationWillBeLost();
			
			// Select another user
			if(index<listModel.size()) {
				employeeList.setSelectedIndex(index);
				employeeList.ensureIndexIsVisible(index);
			} else if(!listModel.isEmpty()) {
				employeeList.setSelectedIndex(listModel.size()-1);
				employeeList.ensureIndexIsVisible(listModel.size()-1);
			}
		}
	}
	
	class CommitListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			int index = employeeList.getSelectedIndex();
			if(currentEmployee.getFullName().trim().length() > 1) {
			uac.commitToDatabase();
			terminationReasonList.commitToDatabase();
			jobTitleList.commitToDatabase();
			allEmployees.commitToDatabase();
			syncListModel();
			employeeList.setSelectedIndex(index);
			employeeList.ensureIndexIsVisible(index);
			commitButton.setEnabled(false);
			informationHasBeenSaved();
			JOptionPane.showConfirmDialog(null, 
					"Changes have been saved to the database.",
					"Saved!",
					JOptionPane.DEFAULT_OPTION,
					JOptionPane.INFORMATION_MESSAGE);
			} else {
				JOptionPane.showConfirmDialog(null, 
						"Either the first name or last name fields should be non-blank!",
						"Not saved!",
						JOptionPane.DEFAULT_OPTION,
						JOptionPane.WARNING_MESSAGE);
			}
		}
	}
	
	class LinkListener implements ActionListener {

		@Override
		public void actionPerformed(ActionEvent arg0) {
			if(isDBOutOfSync()) {
				JOptionPane.showMessageDialog(null, "Save changes to DB before proceeding.", "Data must be saved", JOptionPane.INFORMATION_MESSAGE);
			} else {
				if(uac.isEmployeeLinked(currentEmployee)) {
					UserAccount ua = uac.getLinkedUserAccount(currentEmployee);
					JOptionPane.showMessageDialog(null, "Employee is already linked to user account " + ua.getUserName(), "Employee already linked", JOptionPane.INFORMATION_MESSAGE);
				} else {
				Iterator<UserAccount> i = uac.iterator();
				while(i.hasNext()) {
					if(i.next().isLinked()) {
						i.remove();
					}
				}
				DBJFrame<UserAccountControl, UserAccount> frame = new DBJFrame<UserAccountControl, UserAccount>(uac);
				frame.showDialog("Choose account to link to");
				if(frame.getSelectedRowObject()!=null) {
				frame.getSelectedRowObject().linkToEmployee(currentEmployee);
				}
				}
			}
			
		}
		
	}
	
	//////////////////////
	//// Pop-up Menus ////
	//////////////////////
	
	

	@Override
	public void actionPerformed(ActionEvent arg0) {
		// TODO Auto-generated method stub
		
	}

}
